#!/bin/bash

# SMock 构建脚本 - 用于生成单文件部署的可执行文件

set -e

# 颜色定义
GREEN="\033[0;32m"
YELLOW="\033[0;33m"
NC="\033[0m" # No Color

echo -e "${GREEN}===== SMock 单文件构建脚本 =====${NC}"

# 检查必要工具
command -v go >/dev/null 2>&1 || { echo -e "${YELLOW}错误: 需要安装 Go 但未找到${NC}" >&2; exit 1; }
command -v npm >/dev/null 2>&1 || { echo -e "${YELLOW}错误: 需要安装 npm 但未找到${NC}" >&2; exit 1; }

# 创建输出目录
mkdir -p ./dist

# 构建前端
echo -e "${GREEN}1. 构建前端资源...${NC}"
cd ./frontend
npm install
npm run build
cd ..

# 修改后端代码以嵌入前端资源
echo -e "${GREEN}2. 准备嵌入前端资源...${NC}"

# 创建embed.go文件
cat > ./backend/embed.go << EOF
package main

import (
	"embed"
	"io/fs"
	"net/http"
	"strings"

	"github.com/gin-gonic/gin"
)

//go:embed public/*
var embeddedFiles embed.FS

// 设置嵌入式文件系统
func setupEmbeddedFileSystem(r *gin.Engine) {
	fe, _ := fs.Sub(embeddedFiles, "public")
	r.StaticFS("/", http.FS(fe))

	// 处理SPA路由
	r.NoRoute(func(c *gin.Context) {
		path := c.Request.URL.Path

		// 如果是API请求，交给API处理
		if strings.HasPrefix(path, "/api/") {
			return
		}

		// 返回index.html以支持前端路由
		c.FileFromFS("index.html", http.FS(fe))
	})
}
EOF

# 修改main.go以使用嵌入式文件系统
echo -e "${GREEN}3. 修改主程序以支持嵌入式文件系统...${NC}"

# 创建临时目录并复制后端代码
mkdir -p ./temp
cp -r ./backend/* ./temp/

# 修改main.go文件
cat > ./temp/main.go << EOF
package main

import (
	"log"
	"os"
	"path/filepath"

	"github.com/gin-gonic/gin"
	"github.com/diogoxiang/smock/database"
	"github.com/diogoxiang/smock/controllers"
	"github.com/diogoxiang/smock/services"
)

func main() {
	// 设置数据库路径
	dbPath := os.Getenv("DB_PATH")
	if dbPath == "" {
		// 获取可执行文件所在目录
		exePath, err := os.Executable()
		if err == nil {
			exeDir := filepath.Dir(exePath)
			// 创建数据目录
			dataDir := filepath.Join(exeDir, "data")
			os.MkdirAll(dataDir, 0755)
			dbPath = filepath.Join(dataDir, "sqlite.db")
		} else {
			dbPath = "data/sqlite.db"
		}
	}

	// 设置数据库路径环境变量
	os.Setenv("DB_PATH", dbPath)

	// 初始化数据库
	database.InitDB()

	// 创建Gin实例
	r := gin.Default()

	// 允许跨域
	r.Use(func(c *gin.Context) {
		c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
		c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
		c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")
		c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT, DELETE")

		if c.Request.Method == "OPTIONS" {
			c.AbortWithStatus(204)
			return
		}

		c.Next()
	})

	// 设置嵌入式文件系统
	setupEmbeddedFileSystem(r)

	// API路由组
	api := r.Group("/api")
	{
		// Mock API管理
		api.GET("/mock", controllers.GetAllMockAPIs)
		api.GET("/mock/:id", controllers.GetMockAPI)
		api.POST("/mock", controllers.CreateMockAPI)
		api.PUT("/mock/:id", controllers.UpdateMockAPI)
		api.DELETE("/mock/:id", controllers.DeleteMockAPI)

		// 历史记录API
		api.GET("/logs", controllers.GetAllRequestLogs)
		api.GET("/logs/:id", controllers.GetRequestLog)
		api.DELETE("/logs/:id", controllers.DeleteRequestLog)
		api.DELETE("/logs", controllers.ClearRequestLogs)
	}

	// Mock服务路由 - 所有未匹配的路由都会被当作mock请求处理
	r.NoRoute(services.HandleMockRequest)

	// 获取端口配置
	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
	}

	// 启动服务器
	log.Println("Server started on http://localhost:" + port)
	if err := r.Run(":" + port); err != nil {
		log.Fatal("Failed to start server:", err)
	}
}
EOF

# 修改数据库初始化代码
cat > ./temp/database/db.go << EOF
package database

import (
	"log"
	"os"

	"github.com/diogoxiang/smock/models"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
)

var DB *gorm.DB

// InitDB 初始化数据库连接
func InitDB() {
	var err error
	
	// 从环境变量获取数据库路径
	dbPath := os.Getenv("DB_PATH")
	if dbPath == "" {
		dbPath = "database/sqlite.db"
	}
	
	log.Println("Using database at:", dbPath)
	
	DB, err = gorm.Open(sqlite.Open(dbPath), &gorm.Config{})
	if err != nil {
		log.Fatal("Failed to connect database:", err)
	}

	// 自动迁移数据库模型
	err = DB.AutoMigrate(
		&models.MockAPI{},
		&models.MockResponse{},
		&models.MatchRule{},
		&models.RequestLog{},
	)
	if err != nil {
		log.Fatal("Failed to migrate database:", err)
	}
}
EOF

# 复制前端构建结果到public目录
echo -e "${GREEN}4. 复制前端资源...${NC}"
mkdir -p ./temp/public
cp -r ./frontend/dist/* ./temp/public/

# 交叉编译
echo -e "${GREEN}5. 开始交叉编译...${NC}"
cd ./temp

# 确保启用CGO以支持SQLite
export CGO_ENABLED=1

# 为不同平台构建
echo -e "${YELLOW}注意: 交叉编译需要安装对应平台的C编译器${NC}"

# Linux AMD64
echo -e "${GREEN}构建 Linux (amd64) 版本...${NC}"
GOOS=linux GOARCH=amd64 go build -o ../dist/smock-linux-amd64 .

# Windows AMD64
echo -e "${GREEN}构建 Windows (amd64) 版本...${NC}"
GOOS=windows GOARCH=amd64 go build -o ../dist/smock-windows-amd64.exe .

# MacOS AMD64
echo -e "${GREEN}构建 MacOS (amd64) 版本...${NC}"
GOOS=darwin GOARCH=amd64 go build -o ../dist/smock-macos-amd64 .

# MacOS ARM64 (M1/M2)
echo -e "${GREEN}构建 MacOS (arm64) 版本...${NC}"
GOOS=darwin GOARCH=arm64 go build -o ../dist/smock-macos-arm64 .

cd ..

# 清理临时文件
echo -e "${GREEN}6. 清理临时文件...${NC}"
rm -rf ./temp

echo -e "${GREEN}===== 构建完成 =====${NC}"
echo -e "可执行文件位于 ./dist/ 目录下"
echo -e "使用方法: ./smock-<平台>"
echo -e "数据将保存在可执行文件同目录下的 data/sqlite.db 中"